{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import gzip\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.neighbors import KNeighborsClassifier"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Information"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "http://yann.lecun.com/exdb/mnist/\n",
    "\n",
    "IMAGES\n",
    "[offset] [type]          [value]          [description] \n",
    "0000     32 bit integer  0x00000803(2051) magic number \n",
    "0004     32 bit integer  60000            number of images \n",
    "0008     32 bit integer  28               number of rows \n",
    "0012     32 bit integer  28               number of columns \n",
    "0016     unsigned byte   ??               pixel \n",
    "0017     unsigned byte   ??               pixel\n",
    "\n",
    "LABELS\n",
    "[offset] [type]          [value]          [description] \n",
    "0000     32 bit integer  0x00000801(2049) magic number (MSB first) \n",
    "0004     32 bit integer  60000            number of items \n",
    "0008     unsigned byte   ??               label \n",
    "0009     unsigned byte   ??               label "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [],
   "source": [
    "def read_image_file(filename, images):\n",
    "    width = 28\n",
    "    height = 28\n",
    "    N = images\n",
    "\n",
    "    f = gzip.open(filename, 'r')\n",
    "    f.read(16) # skip preamble, 16 bytes\n",
    "    buffer = f.read(width * height * N) # read in \"N\" images as binary data\n",
    "    data = np.frombuffer(buffer, dtype='uint8') # convert binary data to integers : 0 - 255\n",
    "    data = data.reshape(N, width, height, 1) # reshape to Nx28x28x1 (only 1 color channel, b/w)\n",
    "    f.close()\n",
    "    \n",
    "    return data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "def read_label_file(filename, labels):\n",
    "    N = labels\n",
    "    \n",
    "    f = gzip.open(filename, 'r')\n",
    "    f.read(8) # skip preamble, 8 bytes\n",
    "    buffer = f.read(N) # read in \"N\" labels as binary data\n",
    "    data = np.frombuffer(buffer, dtype='uint8') # convert binary data to integers : 0 - 255\n",
    "    f.close()\n",
    "    \n",
    "    return data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Explore"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_6 = read_image_file('train-images-idx3-ubyte.gz', 6)\n",
    "y_6 = read_label_file('train-labels-idx1-ubyte.gz', 6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((6, 28, 28, 1), (6,))"
      ]
     },
     "execution_count": 85,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_6.shape, y_6.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(28, 28, 1)"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_6[0].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([5, 0, 4, 1, 9, 2], dtype=uint8)"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_6"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 6 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure()\n",
    "fig.subplots_adjust(hspace=0.4, wspace=0.4)\n",
    "for i in range(1, 7):\n",
    "    ax = fig.add_subplot(2, 3, i)\n",
    "    ax.imshow(X_6[i-1].squeeze())\n",
    "    ax.set_title(y_6[i-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Data Preparation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train = read_image_file('train-images-idx3-ubyte.gz', 60_000)\n",
    "y_train = read_label_file('train-labels-idx1-ubyte.gz', 60_000)\n",
    "X_test = read_image_file('t10k-images-idx3-ubyte.gz', 10_000)\n",
    "y_test = read_label_file('t10k-labels-idx1-ubyte.gz', 10_000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((60000, 28, 28, 1), (10000, 28, 28, 1))"
      ]
     },
     "execution_count": 111,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train.shape, X_test.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train = X_train.reshape(60_000, 28*28)\n",
    "X_test = X_test.reshape(10_000, 28*28)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((60000, 784), (10000, 784))"
      ]
     },
     "execution_count": 113,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train.shape, X_test.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [],
   "source": [
    "knn = KNeighborsClassifier(n_neighbors=3).fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9705"
      ]
     },
     "execution_count": 116,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "knn.score(X_test, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
